package com.project.javagobang.game;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.project.javagobang.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.LinkedList;
import java.util.Queue;

//这个类表示"匹配器",通过这个类负责完成整个匹配功能
@Component
public class Matcher {
    //创建三个匹配队列
    private Queue<User> normalQueue = new LinkedList<>();
    private Queue<User> highQueue = new LinkedList<>();
    private Queue<User> veryHighQueue = new LinkedList<>();
    @Autowired
    private OnlineUserManager onlineUserManager;
    private ObjectMapper objectMapper = new ObjectMapper();
    @Autowired
    private RoomManager roomManager;

    //操作匹配队列的方法
    //把玩家放到匹配队列中
    public void add(User user) {
        if (user.getScore() < 2000) {
            synchronized (normalQueue) {
                normalQueue.offer(user);
                normalQueue.notify();
            }
            System.out.println("把玩家 " + user.getUserName() + " 加入到了 normalQueue 中!");
        } else if (user.getScore() >= 2000 && user.getScore() <= 3000) {
            synchronized (highQueue) {
                highQueue.offer(user);
                highQueue.notify();
            }
            System.out.println("把玩家 " + user.getUserName() + " 加入到了 highQueue 中!");
        } else {
            synchronized (veryHighQueue) {
                veryHighQueue.offer(user);
                veryHighQueue.notify();
            }
            System.out.println("把玩家 " + user.getUserName() + " 加入到了 veryHighQueue 中!");
        }
    }

    //当玩家点击停止匹配是,就需要将玩家从匹配队列中删除
    public void remove(User user) {
        if (user.getScore() < 2000) {
            synchronized (normalQueue) {
                normalQueue.remove(user);
            }
            System.out.println("把玩家 " + user.getUserName() + " 从 normalQueue 中删除!");
        } else if (user.getScore() >= 2000 && user.getScore() <= 3000) {
            synchronized (highQueue) {
                highQueue.remove(user);
            }
            System.out.println("把玩家 " + user.getUserName() + " 从 highQueue 中删除!");
        } else {
            synchronized (veryHighQueue) {
                veryHighQueue.remove(user);
            }
            System.out.println("把玩家 " + user.getUserName() + " 从 veryHighQueue 中删除!");
        }
    }

    public Matcher() {
        //创建三个线程,分别针对三个匹配队列,进行操作
        Thread t1 = new Thread() {
            @Override
            public void run() {
                //扫描normalQueue
                while (true) {
                    handlermatch(normalQueue);
                }
            }
        };
        t1.start();

        Thread t2 = new Thread() {
            @Override
            public void run() {
                //扫描highQueue
                while (true) {
                    handlermatch(highQueue);
                }
            }
        };
        t2.start();

        Thread t3 = new Thread() {
            @Override
            public void run() {
                //扫描veryHighQueue
                while (true) {
                    handlermatch(veryHighQueue);
                }
            }
        };
        t3.start();
    }

    private void handlermatch(Queue<User> matchQueue) {
        synchronized (matchQueue) {
            try {
                //1.检测队列中元素个数是否达到2
                //队列的初始情况可能是空。
                // 如果往队列中添加一个元素，这个时候，仍然是不能进行后续匹配操作的。
                // 因此在这里使用while循环检查是更合理的~
                while (matchQueue.size() < 2) {
                    matchQueue.wait();
                }
                //2.尝试从队列中取出两个玩家
                User player1 = matchQueue.poll();
                User player2 = matchQueue.poll();
                System.out.println("匹配出两个玩家: " + player1.getUserName() + "," + player2.getUserName());

                //3.获取到玩家的websocket的会话
                //获取到会话的目的是为了告诉玩家,你排到了
                WebSocketSession session1 = onlineUserManager.getFromGameHall(player1.getUserId());
                WebSocketSession session2 = onlineUserManager.getFromGameHall(player2.getUserId());
                //理伦上来说,匹配队列中的元素一定处于在线的状态
                //我们前面的逻辑已经判断过,当玩家断开连接的时候就已经把他从匹配队列移除了
                //但是仍然进行一次判定
                if (session1 == null) {
                    //如果玩家1现在不在线,就把玩家2重新放回到匹配队列
                    matchQueue.offer(player2);
                    return;
                }
                if (session2 == null) {
                    //如果玩家2现在不在线,就把玩家1重新放回到匹配队列
                    matchQueue.offer(player1);
                    return;
                }
                //当前能否排到两个玩家是同一个用户的情况嘛？一个玩家入队列了两次？理论上也不会存在~~
                //1）如果玩家下线，就会对玩家移出匹配队列。
                //2）又禁止写玩家多开
                //但是仍然这里多进行一次判定,以免前面的逻辑出现bug是带来严重的后果
                if (session1 == session2) {
                    //把其中的一个玩家返回匹配队列
                    matchQueue.offer(player1);
                    return;
                }
                //4. TODO 把这两个玩家放到一个游戏房间中
                Room room = new Room();
                roomManager.add(room, player1.getUserId(), player2.getUserId());
                //5.给玩家反馈信息,通过websocket返回一个message为'matchSuccess'这样的响应
                //此处是要给两个玩家都返回"匹配成功"这样的信息,需要返回两次
                MatchResponse response1 = new MatchResponse();
                response1.setOk(true);
                response1.setMessage("matchSuccess");
                session1.sendMessage(new TextMessage(objectMapper.writeValueAsString(response1)));

                MatchResponse response2 = new MatchResponse();
                response2.setOk(true);
                response2.setMessage("matchSuccess");
                session2.sendMessage(new TextMessage(objectMapper.writeValueAsString(response2)));
            } catch (IOException  | InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
